<?php

namespace App\Console\Commands\Article;

use App\Models\Article\ArticleModel;
use App\Models\Article\ArticleStatisticsDayModel;
use App\Models\Article\ArticleStatisticsLogsModel;
use App\Service\Article\ArticleOperateService;
use Carbon\Carbon;
use Illuminate\Console\Command;

class ArticleStatisticsDay extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'article:statistics_day_script {day?}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '昨天文章数据统计落库';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $day = $this->argument('day');
        if (!$day) {
            $day = date('Y-m-d', strtotime('-1 day'));//昨天时间
        }

        $startTime = strtotime($day);
        $endTime   = $startTime + 86399;
        $createdAt = time();

        ArticleStatisticsDayModel::query()->where('dateAt', $startTime)->update(['isDeleted' => 1]);

        //查询所有文章的 1: 点赞数, 2:收藏数 3:转发数 4:阅读数 5:展示数
        self::totalArticleStatistics($startTime, $endTime, $createdAt);

        //查询单个文章的 1: 点赞数, 2:收藏数 3:转发数 4:阅读数 5:展示数
        self::oneArticleStatistics($startTime, $endTime, $createdAt);

        // 删除历史数据
        self::deleteHistoryData();
    }

    /**
     * 单个文章的数据统计
     * @param $startTime
     * @param $endTime
     * @param $createdAt
     */
    public function oneArticleStatistics($startTime, $endTime, $createdAt)
    {
        $batchData = [];
        foreach (ArticleStatisticsLogsModel::TYPE_TEXT as $type => $typeText) {
            $this->info('文章数据统计:' . $typeText);
            $column = ArticleStatisticsLogsModel::getColumn($type);
            $source = ArticleStatisticsLogsModel::getSource($type);
            if (!$source || !$column) {
                $this->info('文章数据统计类型不匹配 type:' . $type . ' source:' . $source . ' column:' . $column);
                continue;
            }

            // 不同类型的数据
            ArticleStatisticsLogsModel::query()
                ->where('type', $type)
                ->whereBetween('createdAt', [$startTime, $endTime])
                ->selectRaw("articleId,type,count(1) num")
                ->groupBy('articleId')
                ->chunk(
                    500, function ($item) use ($createdAt, $column, $startTime, $type, $source, &$batchData) {
                    $articleIds  = collect($item)->pluck('articleId')->unique()->toArray();
                    $articleList = ArticleModel::query()
                        ->whereIn('id', $articleIds)
                        ->get()->keyBy('id')->toArray();

                    foreach ($item as $v) {
                        $key       = $v->articleId . '-' . $source;
                        $cancelNum = in_array($type, array_keys(ArticleStatisticsLogsModel::TYPE_CANCEL_TEXT)) ? $v->num : 0;//取消
                        $num       = $v->num;
                        if ($cancelNum > 0) {
                            $num = '-' . $v->num;
                        }
                        $num = (int)$num;
                        if (isset($batchData[$key])) {
                            $batchData[$key]['newNum']    += $num;
                            $batchData[$key]['cancelNum'] += $cancelNum;
                            $batchData[$key]['netIncNum'] = $batchData[$key]['netIncNum'] - $batchData[$key]['cancelNum'];
                            continue;
                        }
                        $batchData[$key] = [
                            'dateAt'      => $startTime,                                                        //统计日
                            'articleId'   => $v->articleId,                                                     //文章 ID, 0为所有
                            'source'      => $source,                                                           //数据来源 1: 点赞数, 2:收藏数 3:转发数 4:阅读数 5:展示数
                            'cumulateNum' => $articleList[$v->articleId][$column] ?? 0,                         //累计
                            'newNum'      => $num,                                                              //新增
                            'cancelNum'   => $cancelNum,                                                        //取消
                            'netIncNum'   => $num - $cancelNum,                                                 //净增
                            'createdAt'   => $createdAt,
                        ];
                    }
                },
                );
        }
        if ($batchData) {
            $this->info('文章数据统计数据:' . count($batchData));
            ArticleStatisticsDayModel::batchInsertData($batchData);
        }
    }

    /**
     * 所有文章的数据统计
     * @param $startTime
     * @param $endTime
     * @param $createdAt
     */
    public function totalArticleStatistics($startTime, $endTime, $createdAt)
    {
        // 总数据
        $totalData = ArticleModel::query()
//            ->where('status', ArticleModel::STATUS_ON)
            ->whereIn("publishType", array_keys(ArticleModel::PUBLISH_NO_DRAFT_TYPE_TEXT))
            ->selectRaw(
                "
            sum(supportNum) supportNumTotal,
            sum(collectNum) collectNumTotal,
            sum(forwardNum) forwardNumTotal,
            sum(readNum) readNumTotal,
            sum(showNum) showNumTotal,
            count(1) totalCount
            ",
            )->first();

        // redis缓存的数据
        $totalRedisData = ArticleOperateService::getTotalArticleRedisData(date('Ymd', $startTime), 0);

        // 取消操作的数据
        $getCancelData = ArticleStatisticsLogsModel::query()
            ->whereBetween('createdAt', [$startTime, $endTime])
            ->whereIn('type', array_keys(ArticleStatisticsLogsModel::TYPE_CANCEL_TEXT))
            ->selectRaw("type,count(1) num")
            ->get()->keyBy('type')->toArray();

        $batchTotalData = [];
        foreach (ArticleStatisticsDayModel::TYPE_TEXT as $key => $typeText) {
            $this->info('所有文章的数据统计类型:' . $typeText);
            $cumulateNum = $newNum = $cancelNum = $netIncNum = 0;
            switch ($key) {
                case ArticleStatisticsDayModel::TYPE_LIKE:
                    $cumulateNum = $totalData['supportNumTotal'] ?? 0;
                    $newNum      = $totalRedisData['supportNum'] ?? 0;
                    $cancelNum   = $getCancelData[ArticleStatisticsLogsModel::TYPE_CANCEL_LIKE]['num'] ?? 0;
                    break;
                case ArticleStatisticsDayModel::TYPE_COLLECT:
                    $cumulateNum = $totalData['collectNumTotal'] ?? 0;
                    $newNum      = $totalRedisData['collectNum'] ?? 0;
                    $cancelNum   = $getCancelData[ArticleStatisticsLogsModel::TYPE_CANCEL_COLLECT]['num'] ?? 0;
                    break;
                case ArticleStatisticsDayModel::TYPE_SHARE:
                    $cumulateNum = $totalData['forwardNumTotal'] ?? 0;
                    $newNum      = $totalRedisData['forwardNum'] ?? 0;
                    break;
                case ArticleStatisticsDayModel::TYPE_READ:
                    $cumulateNum = $totalData['readNumTotal'] ?? 0;
                    $newNum      = $totalRedisData['readNum'] ?? 0;
                    break;
                case ArticleStatisticsDayModel::TYPE_SHOW:
                    $cumulateNum = $totalData['showNumTotal'] ?? 0;
                    $newNum      = $totalRedisData['showNum'] ?? 0;
                    break;
                case ArticleStatisticsDayModel::TYPE_ARTICLE:
                    $cumulateNum = $totalData['totalCount'] ?? 0;
                    $newNum      = $cumulateNum;
                    break;
            }

            $netIncNum        = $newNum - $cancelNum;
            $batchTotalData[] = [
                'dateAt'      => $startTime,                                                           //统计日
                'articleId'   => 0,                                                                    //文章 ID, 0为所有
                'source'      => $key,                                                                 //数据来源 1: 点赞数, 2:收藏数 3:转发数 4:阅读数 5:展示数
                'cumulateNum' => $cumulateNum,                                                         //累计
                'newNum'      => $newNum,                                                              //新增
                'cancelNum'   => $cancelNum,                                                           //取消
                'netIncNum'   => $netIncNum,                                                           //净增
                'createdAt'   => $createdAt,
            ];
        }
        if ($batchTotalData) {
            $this->info('所有文章的数据数量:' . count($batchTotalData));
            ArticleStatisticsDayModel::batchInsertData($batchTotalData);
        }

    }

    public static function deleteHistoryData()
    {
        // 保留一个月(15Day)的数据

        // 获得一个月外的id
        $lastMonthTimestamp = Carbon::now()->subDays(15)->endOfDay()->timestamp;
        $lastMonthId        = (int)ArticleStatisticsLogsModel::query()
            ->where('createdAt', '<', $lastMonthTimestamp)
            ->orderByDesc('id')
            ->value('id');

        // 删除小于这个ID的
        do {
            $deletedRows = ArticleStatisticsLogsModel::query()
                ->where('id', '<', $lastMonthId)
                ->limit(10000)
                ->delete();
        } while ($deletedRows > 0);
    }
}
